home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: Alpha / Whiteline Alpha.iso / progtool / modula2 / hk_lib / def_mod / queues.mod < prev    next >
Encoding:
Modula Implementation  |  1994-09-22  |  21.6 KB  |  592 lines

  1. IMPLEMENTATION MODULE  Queues;
  2.  
  3. (*****************************************************************************)
  4. (* Vor saemtlichen Operationen mit den Queues steht folgende Abfrage:        *)
  5. (*                                                                           *)
  6. (*       IF  ( queue # NIL ) & ( queue^.queueAdr = ADR( queue ))  THEN       *)
  7. (*                                                                           *)
  8. (* Sie garantiert mit ziemlicher Sicherheit, dass die uebergebene Queuevari- *)
  9. (* able einen definierten Wert hat, d.h. mit "Create" erzeugt wurde, und     *)
  10. (* nicht irgendein Pointer ist, der irgendwohin zeigt.                       *)
  11. (* Dazu ist es natuerlich noetig, dass die Queuevariablen auch immer als     *)
  12. (* VAR-Parameter uebergeben werden, denn sonst hat man nur eine Kopie der    *)
  13. (* Queue bzw. des Pointers auf die Queue, und die Adresse der Kopie ist      *)
  14. (* sicherlich eine andere als die der Originalqueue.                         *)
  15. (*                                                                           *)
  16. (* Bei dynamischen Datenstrukturen wie so einer Warteschlange steht man vor  *)
  17. (* dem Problem der Speicherverwaltung. Einerseits sollen die Operationen     *)
  18. (* schnell erfolgen, andererseits soll aber kein Speicher verschwendet wer-  *)
  19. (* den.                                                                      *)
  20. (* Wird fuer die Struktur ein statischer Speicherbereich zu Uebersetzungszeit*)
  21. (* festgelegt, so sind die Queueoperationen sicherlich schnell, da zur Lauf- *)
  22. (* zeit kein Speicher angefordert und freigegeben werden muss. Allerdings    *)
  23. (* kann der einmal festgelegte Speicher in der Groesse nicht mehr veraendert *)
  24. (* werden; d.h. es kann sowohl sein, dass der Speicher zur Laufzeit nicht    *)
  25. (* mehr ausreicht, als auch, dass der Speicher die meiste Zeit unbenutzt     *)
  26. (* bleibt.                                                                   *)
  27. (* Wird hingegen fuer jedes neu in die Queue einzufuegendes Element ein neuer*)
  28. (* Speicherblock angefordert, bzw. beim Herausnehmen des Elements freigege-  *)
  29. (* ben, so wird der Speicher zwar optimal ausgenutzt, aber die Operationen   *)
  30. (* werden entsprechend langsam.                                              *)
  31. (*                                                                           *)
  32. (* Da die Art des Zugriffs bei Queues ( und auch bei Stacks ) genau bekannt  *)
  33. (* ist - naemlich am Ende anfuegen, vom Anfang entfernen, keine anderen Zu-  *)
  34. (* griffe -, kann ein Kompromiss zwischen Geschwindigkeit und Speicheraus-   *)
  35. (* nutzung geschlossen werden:                                               *)
  36. (* Speicher wird nicht fuer jedes neue Element angefordert und freigegeben,  *)
  37. (* sondern immer in Bloecken zu mehreren Elementen, d.h. erst wenn ein Block *)
  38. (* voll ist, wird wieder ein neuer Speicherblock angefordert, und erst wenn  *)
  39. (* ein Block leer ist, wird der Speicher fuer ihn freigegeben. Die Bloecke   *)
  40. (* sind durch eine lineare Liste mit Header verbunden. Im Header sind unter  *)
  41. (* anderem die Adressen des ersten und letzten Blocks enthalten, so dass ohne*)
  42. (* die Liste zu durchsuchen sowohl auf das Frontelement als auch das letzte  *)
  43. (* Element zugegriffen werden kann. Die Verzeigerung ist in folgendem Dia-   *)
  44. (* gramm dargestellt, fuer genauere Informationen sollte der Quelltext durch-*)
  45. (* geackert werden.                                                          *)
  46. (*                                                                           *)
  47. (*       queue                erster Block           letzter Block           *)
  48. (*                                                                           *)
  49. (*          |<----                                                           *)
  50. (*          |     |         ________________        ________________         *)
  51. (*  ________V_____|_       |                |      :                :        *)
  52. (* | queueAdr       |      |   belegt       |      :   noch frei    :        *)
  53. (* |----------------|      |----------------|      :................:        *)
  54. (* :                :   -->| erstes Element |   -->: letztes Element:        *)
  55. (* |----------------|  |   |................|  |   :----------------:        *)
  56. (* | queueFront     |--    :  wieder frei   :  |   :    belegt      :        *)
  57. (* |----------------|      |----------------|  |   |----------------|        *)
  58. (* | frontBlock     |----->| naechsterBlock |-~~~~>|     NIL        |        *)
  59. (* |----------------|      |________________|  |   |________________|        *)
  60. (* | queueTail      |--------------------------          ^                   *)
  61. (* |----------------|                                    |                   *)
  62. (* | tailBlock      |------------------------------------                    *)
  63. (* |________________|                                                        *)
  64. (*                                                                           *)
  65. (*___________________________________________________________________________*)
  66. (*   30-Dez-89 , hk                                                          *)
  67. (*         Beginn                                                            *)
  68. (*   01-Jan-90 , hk                                                          *)
  69. (*         Es werden wirklich Werte in die Queue kopiert ( wie in "Stacks" ),*)
  70. (*         nicht nur Verweise auf sie;                                       *)
  71. (*   24-Feb-90 , hk                                                          *)
  72. (*         voellig neue Block-Speicherverwaltung, automatischer Errorhandler *)
  73. (*         <done> als Prozedurrueckgabe, extra Fehlerrueckgabe mit           *)
  74. (*         "LastQueueResult"                                                 *)
  75. (*****************************************************************************)
  76.  
  77.  
  78. FROM   SYSTEM   IMPORT  (* TYPE *)  ADDRESS, BYTE,
  79.                         (* PROC *)  VAL, INLINE, ADR, LONG;
  80.  
  81. FROM   HEAP     IMPORT  (* PROC *)  Allocate, Deallocate;   (* = Storage ?? *)
  82.  
  83. IMPORT MEMORY;    (*    (* TYPE *)  CopyProc,
  84.                         (* PROC *)  ClearMem, CopySmallMem, CopyMem;
  85.                    *)
  86.  
  87. (* ===========================  T Y P E N  ================================= *)
  88.  
  89. TYPE
  90.       block     = POINTER TO  block;
  91.  
  92.  
  93.       Queue     = POINTER TO  QueueInfo;
  94.  
  95.       QueueInfo = RECORD
  96.          queueAdr     : ADDRESS;          (* Adresse einer Queue          *)
  97.          Copy         : MEMORY.CopyProc;  (* Prozedur fuers Wertekopieren *)
  98.          elemSize     : CARDINAL;         (* Groesse eines Queueelements  *)
  99.          maxElement   : LONGINT;          (* Max. Elementindex im Block   *)
  100.          blockSize    : LONGCARD;         (* Groesse eines Speicherblocks *)
  101.          Elemente     : CARDINAL;         (* Anzahl der Queueelemente     *)
  102.          frontElement : LONGINT;          (* Index des ersten Elements    *)
  103.                                           (* im ersten Block              *)
  104.          queueFront   : ADDRESS;          (* Adr. des ersten Elements     *)
  105.          frontBlock   : block;            (* Adr. des ersten Blocks       *)
  106.          tailElement  : LONGINT;          (* Index des letzten Elementes  *)
  107.                                           (* im letzten Block             *)
  108.          queueTail    : ADDRESS;          (* Adr. des letzten Elements    *)
  109.          tailBlock    : block;            (* Adr. des letzten Blocks      *)
  110.       END;
  111.  
  112.  
  113. (* ========================================================================= *)
  114. (* =======================   L O K A L   =================================== *)
  115.  
  116. VAR
  117.      lastResult   : QueueResult;
  118.  
  119.      Queuehandler : QueueHandler;
  120.      handlerOn    : BOOLEAN;
  121.  
  122. (* ------------------------------------------------------------------------- *)
  123.  
  124. PROCEDURE  emptyQueueHandler ((* EIN/ -- *) proc  : ARRAY OF CHAR;
  125.                               (* EIN/ -- *) qErr  : QueueResult   );
  126. (*T*)
  127. (* nur damit das System nicht abstuerzt, falls aus irgendeinem
  128.    Grund der Handler aktiviert wird, obwohl keiner definiert wurde...
  129. *)
  130.  BEGIN
  131.  END  emptyQueueHandler;
  132.  
  133. (* ------------------------------------------------------------------------- *)
  134.  
  135. PROCEDURE  ReleaseBlock ((* EIN/AUS *) VAR queue : Queue );
  136. (*T*)
  137. (* Lokale Hilfsprozedur fuer "Delete","Clear" und "Remove".
  138.    Entfernt ohne Sicherheitsabfrage den ersten Block der Queue
  139.    und gibt dessen Speicherplatz frei.
  140. *)
  141.    VAR  alterBlock : block;
  142.  
  143.    BEGIN
  144.      WITH  queue^  DO
  145.        alterBlock := frontBlock;   (* Element muss referenzierbar *)
  146.                                    (* bleiben                     *)
  147.        frontBlock := frontBlock^;  (* Element aus der Zeigerkette *)
  148.                                    (* nehmen                      *)
  149.        Deallocate( alterBlock, blockSize );
  150.      END; (* WITH *)
  151.    END  ReleaseBlock;
  152.  
  153.  
  154. (* Ende LOKAL ============================================================== *)
  155.  
  156. PROCEDURE  LastQueueResult ( ): QueueResult;
  157. (*T*)
  158.  BEGIN
  159.    RETURN( lastResult );
  160.  END  LastQueueResult;
  161.  
  162. (* ------------------------------------------------------------------------- *)
  163.  
  164. PROCEDURE  AssignQueueHandler ((* EIN/ -- *) handler : QueueHandler );
  165. (*T*)
  166.  BEGIN
  167.    Queuehandler := handler;
  168.    handlerOn    := TRUE;
  169.    lastResult   := queueOk;
  170.  END  AssignQueueHandler;
  171.  
  172. (* ------------------------------------------------------------------------- *)
  173.  
  174. PROCEDURE  UnAssignQueueHandler;
  175. (*T*)
  176.  BEGIN
  177.    handlerOn    := FALSE;
  178.    Queuehandler := emptyQueueHandler;    (* sicherheitshalber *)
  179.    lastResult   := queueOk;
  180.  END  UnAssignQueueHandler;
  181.  
  182. (* ------------------------------------------------------------------------- *)
  183.  
  184. PROCEDURE  Create ((* EIN/ -- *)     groesse : CARDINAL;
  185.                    (* EIN/ -- *)     blkElem : CARDINAL;
  186.                    (* -- /AUS *) VAR queue   : Queue;
  187.                    (* -- /AUS *) VAR done    : BOOLEAN  );
  188. (*T*)
  189.   CONST  procName = 'Create';
  190.  
  191.   BEGIN
  192.     IF  groesse = 0  THEN  groesse := 1;  END;
  193.     IF  blkElem = 0  THEN  blkElem := 1;  END;
  194.  
  195.     done := FALSE;
  196.  
  197.     Allocate( queue, SIZE( queue^ ));   (* = NEW( queue )  *)
  198.  
  199.     (* Speicherplatz fuer den Queue-Header *)
  200.  
  201.     IF  queue # NIL  THEN
  202.  
  203.        WITH  queue^  DO
  204.          blockSize := LONG( blkElem ) * LONG( groesse ) + LONG( SIZE( block ));
  205.  
  206.          Allocate( frontBlock, blockSize );
  207.  
  208.          (* Speicherplatz fuer den ersten Block *)
  209.  
  210.          IF  frontBlock # NIL   THEN
  211.  
  212.             frontBlock^ := NIL;   (* auch letzter Block *)
  213.  
  214.             done        := TRUE;
  215.             lastResult  := queueOk;
  216.  
  217.             IF  groesse <= 10  THEN
  218.               (* Bei weniger als 10 Bytes ist diese
  219.                * Prozedur schneller, und ueberlappende
  220.                * Speicherbereiche duerfte es hier eigent-
  221.                * lich nicht geben.
  222.                *)
  223.               Copy := MEMORY.CopySmallMem;
  224.             ELSE
  225.               Copy := MEMORY.CopyMem;
  226.             END; (* IF groesse *)
  227.  
  228.             queueAdr     := ADR( queue ); (* Queue definiert *)
  229.             elemSize     := groesse;
  230.             maxElement   := VAL( LONGINT, blkElem - 1 );
  231.             Elemente     := 0;
  232.             frontElement := 0;
  233.             tailElement  := -1;
  234.             tailBlock    := frontBlock;
  235.             queueFront   := VAL( LONGINT, frontBlock ) + LONG( SIZE( block ));
  236.             queueTail    := queueFront - VAL( ADDRESS, elemSize );
  237.  
  238.             (* 'tailElement' hat den Index -1, damit bei "Insert"
  239.              * der erste Eintrag im Block nicht uebersprungen
  240.              * wird, da hier zuerst der Index hochgezaehlt wird
  241.              * ( der Index zeigt immer aufs aktuelle Element,
  242.              * und bis jetzt steht ja noch keins drin ).
  243.              * 'queueTail' muss dann natuerlich auch die Adresse
  244.              * VOR dem ersten Element erhalten.
  245.              *)
  246.          END; (* IF frontBlock *)
  247.        END; (* WITH queue^ *)
  248.     END; (* IF queue # NIL *)
  249.  
  250.     IF  ~done  THEN
  251.       lastResult := noMem;
  252.       queue      := NIL;
  253.  
  254.       IF  handlerOn  THEN
  255.         Queuehandler( procName, noMem );
  256.       END;
  257.     END; (* IF ~done *)
  258.   END  Create;
  259.  
  260. (* ------------------------------------------------------------------------- *)
  261.  
  262. PROCEDURE  Clear ((* EIN/AUS *) VAR queue : Queue;
  263.                   (* -- /AUS *) VAR done  : BOOLEAN );
  264. (*T*)
  265.   CONST procName = 'Clear';
  266.  
  267.   BEGIN
  268.     IF  ( queue # NIL ) & ( queue^.queueAdr = ADR( queue ))  THEN
  269.  
  270.       WITH  queue^  DO
  271.         WHILE  frontBlock^ # NIL  DO
  272.           ReleaseBlock( queue );(* Alle Bloecke ausser dem letzten entfernen *)
  273.         END; (* WHILE *)
  274.  
  275.         Elemente     := 0;
  276.         frontElement := 0;
  277.         queueFront   := VAL( ADDRESS, frontBlock ) + LONG( SIZE( block ));
  278.         tailElement  := -1;
  279.         queueTail    := queueFront - VAL( ADDRESS, elemSize );
  280.       END; (* WITH queue^ *)
  281.  
  282.       done         := TRUE;
  283.       lastResult   := queueOk;
  284.  
  285.     ELSE (* <queue> undefiniert *)
  286.  
  287.       done       := FALSE;
  288.       lastResult := defErr;
  289.       IF  handlerOn  THEN
  290.         Queuehandler( procName, defErr );
  291.       END;
  292.     END; (* IF queue # NIL *)
  293.  
  294.   END  Clear;
  295.  
  296. (* ------------------------------------------------------------------------- *)
  297.  
  298. PROCEDURE  Delete ((* EIN/AUS *) VAR queue : Queue;
  299.                    (* -- /AUS *) VAR done  : BOOLEAN );
  300. (*T*)
  301.    CONST procName = 'Delete';
  302.  
  303.    BEGIN
  304.      IF  ( queue # NIL ) & ( queue^.queueAdr = ADR( queue ))  THEN
  305.         Clear( queue, done );
  306.  
  307.         (* Jetzt noch den letzten Block und den
  308.          * Queue-Header entfernen.
  309.          *)
  310.  
  311.         Deallocate( queue^.frontBlock, SIZE( queue^.blockSize ));
  312.         Deallocate( queue, SIZE( queue^ ));
  313.  
  314.         queue      := NIL;
  315.  
  316.         done       := TRUE;
  317.         lastResult := queueOk;
  318.  
  319.      ELSE  (* <queue> undefiniert *)
  320.  
  321.         done       := FALSE;
  322.         lastResult := defErr;
  323.         IF  handlerOn  THEN
  324.           Queuehandler( procName, defErr );
  325.         END;
  326.      END; (* IF queue # NIL *)
  327.  
  328.    END  Delete;
  329.  
  330. (* ------------------------------------------------------------------------- *)
  331.  
  332. PROCEDURE  IsEmpty ((* EIN/ -- *) VAR queue : Queue ): BOOLEAN;
  333. (*T*)
  334.   CONST procName = 'IsEmpty';
  335.  
  336.   BEGIN
  337.     IF  ( queue # NIL ) & ( queue^.queueAdr = ADR( queue ))  THEN
  338.        lastResult := queueOk;
  339.  
  340.        RETURN( queue^.Elemente = 0 );
  341.  
  342.     ELSE  (* <queue> undefiniert *)
  343.  
  344.        lastResult := defErr;
  345.        IF  handlerOn  THEN
  346.          Queuehandler( procName, defErr );
  347.        END;
  348.  
  349.        RETURN( TRUE);
  350.     END; (* IF queue # NIL *)
  351.   END  IsEmpty;
  352.  
  353. (* ------------------------------------------------------------------------- *)
  354.  
  355. PROCEDURE  Length ((* EIN/ -- *) VAR queue : Queue ): CARDINAL;
  356. (*T*)
  357.   CONST procName = 'Length';
  358.  
  359.   BEGIN
  360.     IF  ( queue # NIL ) & ( queue^.queueAdr = ADR( queue ))  THEN
  361.       lastResult := queueOk;
  362.  
  363.       RETURN( queue^.Elemente );
  364.  
  365.     ELSE  (* <queue> undefiniert *)
  366.  
  367.       lastResult := defErr;
  368.       IF  handlerOn  THEN
  369.         Queuehandler( procName, defErr );
  370.       END;
  371.  
  372.       RETURN( 0 );
  373.     END; (* IF queue # NIL *)
  374.   END  Length;
  375.  
  376. (* ------------------------------------------------------------------------- *)
  377.  
  378. PROCEDURE  Insert ((* EIN/ -- *)     wert  : ARRAY OF BYTE;
  379.                    (* EIN/AUS *) VAR queue : Queue;
  380.                    (* -- /AUS *) VAR done  : BOOLEAN       );
  381. (*T*)
  382.    CONST procName = 'Insert';
  383.  
  384.    VAR  neuerBlock : block;
  385.  
  386.    BEGIN
  387.      done       := FALSE;   (* wird nur bei Erfolg geaendert *)
  388.      lastResult := defErr;  (* wird je nach Fehler gesetzt   *)
  389.  
  390.      WITH queue^  DO
  391.        IF  ( queue # NIL ) & ( queue^.queueAdr = ADR( queue ))  THEN
  392.  
  393.          IF  elemSize # VAL( CARDINAL, HIGH( wert )) + 1   THEN
  394.  
  395.            (* Der Speicherplatz eines Feldes von BYTES laesst
  396.             * sich natuerlich aus der Obergrenze des Feldes
  397.             * berechnen. Hier stimmt der Speicherbedarf nicht
  398.             * mit der Definition ueberein.
  399.             *)
  400.            lastResult := sizeErr;
  401.  
  402.          ELSE (* Speicherplatz stimmt *)
  403.  
  404.            IF  tailElement < maxElement  THEN
  405.              (* Fuer das neue Element ist noch Platz im Block *)
  406.  
  407.              INC( tailElement );
  408.              INC( queueTail, elemSize );
  409.  
  410.              done := TRUE;
  411.  
  412.            ELSE (* neuer Block faellig *)
  413.  
  414.              (* Der Speicher fuer den neuen Block
  415.               * wird beschafft.
  416.               *)
  417.  
  418.              Allocate( neuerBlock, blockSize );
  419.  
  420.              IF  neuerBlock = NIL  THEN
  421.  
  422.                lastResult:= noMem;  (* Kein Speicher mehr *)
  423.              ELSE (* alles klar *)
  424.  
  425.                neuerBlock^ := NIL;        (* Ende der Liste              *)
  426.                tailBlock^  := neuerBlock; (* an bisher letzten anhaengen *)
  427.                tailBlock   := neuerBlock; (* als neuen letzten merken    *)
  428.  
  429.                tailElement := 0;
  430.                queueTail   := VAL( LONGINT, tailBlock ) + LONG( SIZE( block ));
  431.  
  432.                (* tailElement jetzt nicht -1, da ja gleich ein
  433.                 * Wert in den neuen Block kopiert wird.
  434.                 *)
  435.                done := TRUE;
  436.  
  437.              END; (* IF neuerBlock *)
  438.            END; (* IF tailElement *)
  439.          END; (* IF elemSize *)
  440.        END; (* IF queue # NIL *)
  441.  
  442.        IF  done  THEN
  443.          Copy( ADR( wert ), queueTail, elemSize );
  444.          INC( Elemente );
  445.          lastResult  := queueOk;
  446.  
  447.        ELSE (* Fehler aufgetreten *)
  448.  
  449.          IF  handlerOn  THEN
  450.            Queuehandler( procName, lastResult );
  451.          END;
  452.        END; (* IF done *)
  453.  
  454.      END; (* WITH queue^ *)
  455.  
  456.  
  457.    END  Insert;
  458.  
  459. (* ------------------------------------------------------------------------- *)
  460.  
  461. PROCEDURE  Look ((* EIN/ -- *) VAR queue : Queue;
  462.                  (* -- /AUS *) VAR wert  : ARRAY OF BYTE;
  463.                  (* -- /AUS *) VAR done  : BOOLEAN       );
  464. (*T*)
  465.    CONST procName = 'Look';
  466.  
  467.    BEGIN
  468.      done       := FALSE;
  469.      lastResult := defErr;
  470.  
  471.      WITH queue^  DO
  472.        IF  ( queue # NIL ) & ( queue^.queueAdr = ADR(queue ))  THEN
  473.  
  474.          IF  elemSize # VAL( CARDINAL, HIGH( wert )) + 1   THEN
  475.            lastResult := sizeErr;
  476.  
  477.          ELSE (* Speicherplatz stimmt *)
  478.  
  479.            IF   Elemente = 0   THEN
  480.              lastResult := queueEmpty;  (* nix da *)
  481.  
  482.            ELSE  (* Queue nicht leer *)
  483.              done       := TRUE;
  484.              lastResult := queueOk;
  485.  
  486.              Copy( queueFront, ADR( wert ), elemSize );
  487.            END; (* IF Elemente *)
  488.          END; (* IF elemSize *)
  489.        END; (* IF queue # NIL ... *)
  490.  
  491.        IF  ~done  THEN
  492.          (* Zur Sicherheit den gelieferten
  493.           * ( nicht vorhandenen ) Wert init.
  494.           *)
  495.          MEMORY.ClearMem( ADR( wert ), HIGH( wert ) + 1 );
  496.  
  497.          IF  handlerOn  THEN
  498.            Queuehandler( procName, lastResult );
  499.          END;
  500.        END; (* IF ~done *)
  501.      END; (* WITH queue^ *)
  502.  
  503.    END  Look;
  504.  
  505. (* ------------------------------------------------------------------------- *)
  506.  
  507. PROCEDURE  Remove ((* EIN/AUS *) VAR queue : Queue;
  508.                    (* -- /AUS *) VAR wert  : ARRAY OF BYTE;
  509.                    (* -- /AUS *) VAR done  : BOOLEAN       );
  510. (*T*)
  511.    CONST procName = 'Remove';
  512.  
  513.    BEGIN
  514.      done       := FALSE;
  515.      lastResult := defErr;
  516.  
  517.      IF  ( queue # NIL ) & ( queue^.queueAdr = ADR( queue ))  THEN
  518.  
  519.        WITH queue^  DO
  520.          IF  elemSize # VAL( CARDINAL, HIGH( wert )) + 1   THEN
  521.            lastResult := sizeErr;
  522.  
  523.          ELSE (* Speicherplatz stimmt *)
  524.  
  525.            IF   Elemente = 0   THEN
  526.              lastResult := queueEmpty;
  527.  
  528.            ELSE  (* <queue> nicht leer *)
  529.              done       := TRUE;
  530.              lastResult := queueOk;
  531.  
  532.              Copy( queueFront, ADR( wert ), elemSize );
  533.  
  534.              DEC( Elemente );
  535.  
  536.              IF  ( Elemente > 0 ) & ( frontElement < maxElement )  THEN
  537.  
  538.                (* Wenn noch ein Element in der Queue ist, und das
  539.                 * naechste Element noch innerhalb dieses Blocks ist,
  540.                 * koennen Index und Adresse einfach hochgezaehlt werden.
  541.                 *)
  542.  
  543.                INC( frontElement );
  544.                INC( queueFront, elemSize );
  545.  
  546.              ELSE (* <queue> leer oder lediglich vorderer Block leer *)
  547.  
  548.                IF frontBlock^ # NIL  THEN
  549.  
  550.                  (* Wenn lediglich der vordere Block leer ist,
  551.                   * aber nicht die Queue - d.h. es existieren noch
  552.                   * weitere Bloecke -, den vorderen Block entfernen.
  553.                   * Der Zeiger auf das letzte Element bleibt erhalten.
  554.                   *)
  555.                  ReleaseBlock ( queue );
  556.  
  557.                ELSE  (* <queue> ist leer *)
  558.  
  559.                  tailElement := -1;
  560.                  queueTail   :=   VAL( ADDRESS, frontBlock )
  561.                                 - VAL( ADDRESS, elemSize )
  562.                                 + LONG( SIZE( block ));
  563.                END;
  564.  
  565.                (* Das Frontelement beginnt auf jeden Fall am
  566.                 * Anfang des 'frontBlock's, egal ob in der Queue
  567.                 * noch was drin ist.
  568.                 *)
  569.                frontElement := 0;
  570.                queueFront   := VAL(ADDRESS, frontBlock) + LONG( SIZE( block ));
  571.  
  572.              END; (* IF ( Elemente > 0 )... *)
  573.  
  574.            END; (* IF Elemente *)
  575.          END; (* IF elemSize *)
  576.        END; (* WITH queue^ *)
  577.      END; (* IF queue # NIL ... *)
  578.  
  579.      IF  ~done  THEN
  580.        MEMORY.ClearMem( ADR( wert ), HIGH( wert ) + 1 );
  581.  
  582.        IF  handlerOn  THEN
  583.          Queuehandler( procName, lastResult );
  584.        END;
  585.      END; (* IF ~done *)
  586.  
  587.  
  588.    END  Remove;
  589.  
  590.  
  591. END  Queues.
  592.